structure FindEscape : sig
    val findEscape : Absyn.exp -> unit 
end =
struct
   structure A = Absyn
   structure E = ErrorMsg
   structure S = Symbol

   type depth = int

   type escEnv = (depth * bool ref) S.table

   fun addVar (env, name, d, escape) = ( escape := false
				       ; S.enter (env, name, (d, escape)) )
   fun traverseExp (env, d) =
       let fun escaped name = case S.look (env, name)
			       of NONE => ()
				| SOME (d', r) => if d'<d
						  then r := true
						  else ()


	   and trVar (A.SimpleVar (name, pos)) = escaped name
	     | trVar (A.FieldVar (var, name, pos)) = trVar var 		(* fields are heap allocated, so always escape *)
	     | trVar (A.SubscriptVar (var, exp, pos)) = ( trVar var
							; trExp exp )

	   and trExp (A.VarExp var) = trVar var

	     | trExp (A.NilExp) = ()

	     | trExp (A.IntExp _) = ()

	     | trExp (A.StringExp _) = ()

	     | trExp (A.CallExp{func,args,pos}) = app trExp args
						  
	     | trExp (A.OpExp{left,oper,right,pos}) = ( trExp left
						      ; trExp right )

	     | trExp (A.ArrayExp{typ,size,init,pos}) = ( trExp size
						       ; trExp init )

	     | trExp (A.RecordExp{fields,typ,pos}) = app (fn (_, exp, _) => trExp exp)
							 fields

	     | trExp (A.SeqExp exps) = app (fn (exp, pos) => trExp exp)
					   exps

	     | trExp (A.AssignExp{var,exp,pos}) = ( trExp exp
						  ; trVar var )
						  
	     | trExp (A.IfExp{test,then',else'=NONE,pos}) = ( trExp test
							    ; trExp then' )

	     | trExp (A.IfExp{test,then',else'=SOME else',pos}) = ( trExp test
								  ; trExp then'
								  ; trExp else' )

	     | trExp (A.WhileExp{test,body,pos}) = ( trExp test
						   ; trExp body )

	     | trExp (A.BreakExp _) = ()

	     | trExp (A.LetExp{decs,body,pos}) = let val env = foldl trDec env decs
						 in traverseExp (env, d) body
						 end
	     | trExp (A.ForExp{var,escape,lo,hi,body,pos}) = E.impossible "ESCAPE: FOR-EXP ESCAPED FROM PARSER"
						 
	   and trDec (A.FunctionDec nfs, env) = let fun trFun {name,params,result,body,pos} = let val env = foldl (fn ({name,escape,typ,pos}, env) => addVar (env, name, d+1, escape))
														  env
														  params
											      in traverseExp (env, d+1) body
											      end
						in ( app trFun nfs
						   ; env )
						end
					   
	     | trDec (A.VarDec{name,escape,typ,init,pos}, env) = ( trExp init
								 ; addVar (env, name, d, escape) )
								 
	     | trDec (A.TypeDec nts, env) = env
       in trExp
       end

   val findEscape = traverseExp (S.empty, 0)
end
